/***********************************************************************************
 * 文件名： soft_uart.h
 * 版本： 1
 * 说明：
 * 		软件模拟UART。提供单个字节发送和接收的基本功能，类似于常见MCU的基础UART外设。
 * 修改记录：
 * 	2021/04/28: 初版。 刘言。
***********************************************************************************/
#ifndef _SOFT_UART_H_
#define _SOFT_UART_H_

// 通过修改这里设置正确的配置头文件路径
#include "..\..\..\projects\prj\App\suart_config.h"
//#include "..\App\suart_config.h"

#include "..\..\polsys.h"



typedef enum _suart_ev
{
    SUART_EV_NULL,
    SUART_EV_RX_DONE,   // 一个字节接收完毕
    SUART_EV_STOP_ERR,  // 停止位电平错误（如果SUart_Event处理时间大于3个时钟周期，导致接收停止位时已经达到了下一个起始位，也会导致这个错误），下一次的高电平将会认为是空闲状态
    SUART_EV_TX_DONE,   // 一个字节发送完毕
    _SUART_EV_END
}suart_ev_t;



// 事件函数申明，看做是回调函数
void SUart_Event(suart_ev_t e);


// 内部伪函数

#ifdef _SUART_HALF_DUPLEX
#define _SUart_RxLogic()    \
{\
    if(!_SUart_mSending)\
    {\
        if(_SUart_mRxStep == 0)  /* 等待高电平*/\
        {\
            if(_SUart_GetRxPin())\
            {\
                _SUart_mRxStep = 1;\
            }\
        }\
        else if(_SUart_mRxStep == 1)     /* 等待低电平（第一次检测到的低电平是起始位刚跳变时候）*/\
        {\
            if(!_SUart_GetRxPin())\
            {\
                _SUart_mRxStep = 2;\
            }\
        }\
        else if(_SUart_mRxStep == 2)     /*接收起始位（低电平，这个时刻正常来说处于起始位的中间周期）*/\
        {\
            if(!_SUart_GetRxPin())\
            {\
                _SUart_mRxStep = 3;\
                _SUart_mRxCycCount = 0;\
                _SUart_mRxBitCount = 0;\
            }\
            else\
            {\
                _SUart_mRxStep = 1;      /* 起始位错误，重新等待低电平*/\
            }\
        }\
        else if(_SUart_mRxStep == 3)     /* 接收数据*/\
        {\
            _SUart_mRxCycCount++;\
            if(_SUart_mRxCycCount == 3)\
            {\
                _SUart_mRxCycCount = 0;\
                _SUart_mRxBuff >>= 1;\
                if(_SUart_GetRxPin())\
                {\
                    _SUart_mRxBuff |= 0x80;\
                }\
                _SUart_mRxBitCount++;\
                if(_SUart_mRxBitCount == 8)\
                {\
                    _SUart_mRxStep = 4;\
                    SUart_Event(SUART_EV_RX_DONE);\
                }\
            }\
        }\
        else if(_SUart_mRxStep == 4)     /* 接收停止位（高电平）*/\
        {\
            _SUart_mRxCycCount++;\
            if(_SUart_GetRxPin())\
            {\
                _SUart_mRxStep = 1;      /* 收到了停止位，重新等待低电平(这里有可能依然是最后一位高电平，因为SUart_Event执行时间可能较长会影响停止位的接收，所以没有严格等待3个时钟周期。)*/\
            }\
            else if(_SUart_mRxCycCount == 3)\
            {\
                _SUart_mRxStep = 0;      /* 停止位电平错误，重新等待高电平（如果SUart_Event处理时间大于3个时钟周期也会导致这个错误）*/\
                SUart_Event(SUART_EV_STOP_ERR);\
            }\
        }\
        else\
        {\
            _SUart_mRxStep = 0;\
        }\
    }\
}
#else
#define _SUart_RxLogic()    \
{\
    if(_SUart_mRxStep == 0)  /* 等待高电平*/\
    {\
        if(_SUart_GetRxPin())\
        {\
            _SUart_mRxStep = 1;\
        }\
    }\
    else if(_SUart_mRxStep == 1)     /* 等待低电平（第一次检测到的低电平是起始位刚跳变时候）*/\
    {\
        if(!_SUart_GetRxPin())\
        {\
            _SUart_mRxStep = 2;\
        }\
    }\
    else if(_SUart_mRxStep == 2)     /*接收起始位（低电平，这个时刻正常来说处于起始位的中间周期）*/\
    {\
        if(!_SUart_GetRxPin())\
        {\
            _SUart_mRxStep = 3;\
            _SUart_mRxCycCount = 0;\
            _SUart_mRxBitCount = 0;\
        }\
        else\
        {\
            _SUart_mRxStep = 1;      /* 起始位错误，重新等待低电平*/\
        }\
    }\
    else if(_SUart_mRxStep == 3)     /* 接收数据*/\
    {\
        _SUart_mRxCycCount++;\
        if(_SUart_mRxCycCount == 3)\
        {\
            _SUart_mRxCycCount = 0;\
            _SUart_mRxBuff >>= 1;\
            if(_SUart_GetRxPin())\
            {\
                _SUart_mRxBuff |= 0x80;\
            }\
            _SUart_mRxBitCount++;\
            if(_SUart_mRxBitCount == 8)\
            {\
                _SUart_mRxStep = 4;\
                SUart_Event(SUART_EV_RX_DONE);\
            }\
        }\
    }\
    else if(_SUart_mRxStep == 4)     /* 接收停止位（高电平）*/\
    {\
        _SUart_mRxCycCount++;\
        if(_SUart_GetRxPin())\
        {\
            _SUart_mRxStep = 1;      /* 收到了停止位，重新等待低电平(这里有可能依然是最后一位高电平，因为SUart_Event执行时间可能较长会影响停止位的接收，所以没有严格等待3个时钟周期。)*/\
        }\
        else if(_SUart_mRxCycCount == 3)\
        {\
            _SUart_mRxStep = 0;      /* 停止位电平错误，重新等待高电平（如果SUart_Event处理时间大于3个时钟周期也会导致这个错误）*/\
            SUart_Event(SUART_EV_STOP_ERR);\
        }\
    }\
    else\
    {\
        _SUart_mRxStep = 0;\
    }\
}
#endif

#ifdef _SUART_USE_TX_DONE_EVENT
#define _SUart_EvTxDone()   SUart_Event(SUART_EV_TX_DONE)
#else
#define _SUart_EvTxDone()
#endif

#ifdef _SUART_HALF_DUPLEX
#define _SUart_PinTxDone()  _SUart_PinRxMode()
#else
#define _SUart_PinTxDone()
#endif

#define _SUart_TxLogic()    \
{\
    if(_SUart_mSending)\
    {\
        _SUart_mTxCycCount++;\
        if(_SUart_mTxCycCount == 3)\
        {\
            _SUart_mTxCycCount = 0;\
            if(_SUart_mTxStep == 0)    /* 发送起始位*/\
            {\
                _SUart_SetTxPin(0);\
                _SUart_mTxStep = 1;\
            }\
            else if(_SUart_mTxStep == 1)   /* 发送数据*/\
            {\
                _SUart_SetTxPin(_SUart_mTxBuff & 0x01);\
                _SUart_mTxBuff >>= 1;\
                _SUart_mTxBitCount++;\
                if(_SUart_mTxBitCount == 8)\
                {\
                    _SUart_mTxStep = 2;\
                }\
            }\
            else if(_SUart_mTxStep == 2)   /* 发送结束位*/\
            {\
                _SUart_SetTxPin(1);\
                _SUart_mTxStep = 3;        \
            }\
            else if(_SUart_mTxStep == 3)   /* 发送完毕*/\
            {\
                _SUart_mSending = false;\
                _SUart_EvTxDone();\
                _SUart_PinTxDone();\
            }\
            else\
            {\
                _SUart_mTxStep = 0;\
            }\
        }\
    }\
}
        




// 为了使用伪函数暴露以下属性

extern volatile bit _SUart_Run;

extern volatile u8 _SUart_mRxStep;      // 接收步骤
extern volatile u8 _SUart_mRxCycCount;      // 接收1个位的时钟周期计数
extern volatile u8 _SUart_mRxBitCount;      // 接收位计数
extern volatile u8 _SUart_mRxBuff;           // 接收缓存

extern volatile bit _SUart_mSending;         
extern volatile u8 _SUart_mTxStep;          // 发送步骤
extern volatile u8 _SUart_mTxBuff;          // 发送缓存
extern volatile u8 _SUart_mTxBitCount;      // 发送位计数
extern volatile u8 _SUart_mTxCycCount;      // 发送1个位的时钟周期计数



// API

// 定时器中断中调用，定时器中断频率的 3倍 就是波特率。
#define SUart_EvTimer() \
{\
    if(_SUart_Run)\
    {\
        _SUart_RxLogic();\
        _SUart_TxLogic();\
    }\
}

// 初始化。端口和定时器。注意没有使能，需要调用 SUart_Enable 后 SUart 才开始运行。
#define SUart_Init()    \
{\
    _SUart_InitPin();\
    _SUart_InitTimer();\
}

// 关闭 SUART
#define SUart_Disable()     _SUart_Run = false

// 开启 SUART
#define SUart_Enable()      _SUart_Run = true

// 获取刚刚收到的一个字节，一般在收到 SUART_EV_RX_DONE 事件后调用。
#define SUart_GetRxByte()   _SUart_mRxBuff

// [异步]发送一个字节
// 发送完成后会触发 SUART_EV_TX_DONE 事件（如果使能），也可以调用 SUart_GetTxFlag 查询发送状态。
void SUart_SendByte(u8 byte);

// 获取（查询）发送状态
// 1：发送中，0：发送完毕
#define SUart_GetTxFlag()   _SUart_mSending

#endif
